package no.ntnu.fp.gui.guiElements;

import java.awt.BasicStroke;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Stroke;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowFocusListener;
import java.awt.image.BufferStrategy;
import java.sql.Date;
import java.sql.Time;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JList;
import javax.swing.event.MouseInputListener;

import no.ntnu.fp.gui.CommandCentre;
import no.ntnu.fp.gui.JEmployeeList;
import no.ntnu.fp.gui.Popupmenu;
import no.ntnu.fp.model.Appointment;
import no.ntnu.fp.model.CalendarHelper;
import no.ntnu.fp.model.Person;

public class CalendarPanel2 extends Canvas implements Runnable,
		MouseInputListener {

	BufferStrategy _buffStrategy;
	Graphics2D g2d;
	Thread myThread;
	boolean alive = true;
	long _now = System.currentTimeMillis();
	long lastTime = System.currentTimeMillis();
	Container myContainer;
	CalendarHelper calHelp = new CalendarHelper();
	Popupmenu pop;
	ArrayList<AppointmentBox> abs;
	List<Appointment> aps;
	Stroke nowLineStroke = new BasicStroke(3, BasicStroke.CAP_BUTT,
			BasicStroke.JOIN_BEVEL);
	Stroke basicStroke;
	Color lightGray = new Color(240, 240, 240);

	Date firstVisibleDate, lastVisibleDate;

	int x, y;

	int previusPeerHight, previusPeerWidth;

	int dW, dH;

	LinkedList<String> days = new LinkedList<String>();

	int width, height;
	private final JList jList;

	public CalendarPanel2(Container container, JList jList) {
		// Start: For testing
		// Person.makeExamplesUsers();
		// Person.exampleCurrentUser();
		// Appointment.makeExamples();
		// End: For testing

		myContainer = container;
		this.jList = jList;

		Calendar cal = Calendar.getInstance();
		firstVisibleDate = calHelp.getFirstDayInCurrentWeek();
		lastVisibleDate = calHelp.getLastDayInCurrentWeek();

		addMouseListener(this);
		int[] dayDate = new int[7];
		dayDate = calHelp.getWholeWeekDay();
		String[] daysOfWeek = new String[7];
		daysOfWeek = calHelp.getWholeWeek();

		for (int i = 0; i < dayDate.length; i++) {
			days.add(daysOfWeek[i].substring(0, 3) + " " + dayDate[i]);
		}

		addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyReleased(KeyEvent e) {
				// TODO Auto-generated method stub

			}

			@Override
			public void keyPressed(KeyEvent e) {
				// TODO Auto-generated method stub
				if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
					updatePanelForwardDay();
					CommandCentre.updateWeekMonth();
				}
				if (e.getKeyCode() == KeyEvent.VK_LEFT) {
					updatePanelBackwardDay();
					CommandCentre.updateWeekMonth();
				}
			}
		});

		setFocusable(true);
		requestFocusInWindow();
		requestFocus();
		container.add(this);

		myThread = new Thread(this);

		width = this.getWidth() - 300;
		height = this.getHeight() - 107;
		// end
		myThread.start();
	}

	public void updatePanelForwardWeek() {
		calHelp.jumpWeek();
		// drawText();
		updateDays();
		draw();
	}

	public void updatePaneBackwardWeek() {
		calHelp.jumpBackWeek();
		// drawText();
		updateDays();
		draw();
	}

	public void updatePanelForwardDay() {
		calHelp.jumpDay();
		// drawText();
		updateDays();
		draw();
	}

	public void updatePanelBackwardDay() {
		calHelp.jumpBackDay();
		updateDays();

		// drawText();
		// drawGrid();

		draw();

	}

	public void refreshCalendar() {
		calHelp = new CalendarHelper();
		updateDays();
		// draw();
	}

	public String getFullDate() {
		SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy");
		StringBuilder dvalue = new StringBuilder(sdf.format(calHelp
				.getDateNow()));
		return dvalue.toString();
	}

	public CalendarHelper getCalendarHelper() {
		return calHelp;
	}

	public String getMonth(int a) {
		return calHelp.getMonth(a);
	}

	public int getYear() {
		return calHelp.getYear();
	}

	public int getWeek() {
		return calHelp.getWeek();
	}

	public Date getDate() {
		return calHelp.getDateNow();
	}

	private void updateDays() {
		int[] dayDate = new int[7];
		days = new LinkedList<String>();
		dayDate = calHelp.getWholeWeekDay();
		String[] daysOfWeek = new String[7];
		daysOfWeek = calHelp.getWholeWeek();
		// days.removeAll(days);
		for (int i = 0; i < dayDate.length; i++) {

			days.add(daysOfWeek[i].substring(0, 3) + " " + dayDate[i]);
		}
	}

	public void draw() {

		dH = previusPeerHight - myContainer.getHeight();
		dW = previusPeerWidth - myContainer.getWidth();
		previusPeerHight = myContainer.getHeight();
		previusPeerWidth = myContainer.getWidth();

		// if(dW <0){
		// previusPeerWidth = myContainer.getWidth();
		// }
		// else if(dW >0){
		//
		// }
		// if(dH>0){
		// previusPeerHight = myContainer.getHeight();
		// }
		// System.out.println(myContainer.getX()+" "+myContainer.getY());

		this.setSize(width - dW, height - dH);
		width = width - dW;
		height = height - dH;

		// Clear screen.
		g2d.setColor(Color.WHITE);
		g2d.fillRect(0, 0, width, height);

		x = (int) ((width - 32d) / 7d);
		y = (int) ((height) / 18d);
		
		g2d.setColor(Color.DARK_GRAY);
		drawGrid();
		
		g2d.setColor(Color.BLACK);
		drawText();
		drawAppointments();

		/*
		 * Appointment ape = Appointment.example(); Appointment ape2 =
		 * Appointment.example(18,30,19,00,15); Appointment ape3 =
		 * Appointment.example(06,00,15,00,16);
		 * 
		 * AppointmentBox ab = new AppointmentBox(ape); AppointmentBox ab2 = new
		 * AppointmentBox(ape2); AppointmentBox ab3 = new AppointmentBox(ape3);
		 * 
		 * // int startY =getYposFromDate(ape.getStart()); // int endY
		 * =getYposFromDate(ape.getEnd()); ab.draw(g2d, x, y, width/7, height);
		 * 
		 * // startY =getYposFromDate(ape2.getStart()); // endY
		 * =getYposFromDate(ape2.getEnd());
		 * 
		 * ab2.draw(g2d, x, y, width/7, height);
		 * 
		 * // startY =getYposFromDate(ape3.getStart()); // endY
		 * =getYposFromDate(ape3.getEnd());
		 * 
		 * ab3.draw(g2d, x, y, width/7, height);
		 */

		drawCurrentTimeLine(g2d);

		_buffStrategy.show();
		myContainer.repaint();
		g2d = (Graphics2D) _buffStrategy.getDrawGraphics();
		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
				RenderingHints.VALUE_RENDER_QUALITY);

	}

	private void drawCurrentTimeLine(Graphics2D g2d) {
		if (calHelp.getFirstCalendarDayDate().before(calHelp.getDateNow())
				&& calHelp.getLastDayInCurrentWeek()
						.after(calHelp.getDateNow())) {
			g2d.setColor(Color.RED);

			int X = getXposFromDate(calHelp.getDateNow());
			int Y = getYposFromDate(calHelp.getDateTime());
			if (X != -1 && Y != -1) {
				g2d.setStroke(nowLineStroke);
				g2d.drawLine(X, Y, X + x, Y);
				g2d.setStroke(basicStroke);
			}
		}
	}

	private void drawGrid() {

		g2d.setColor(lightGray);
		// Draw cell shades
		for (int i = 0; i < 18; i += 2) {
			g2d.fillRect(0, i * y, width, y);
		}

		g2d.setColor(Color.BLACK);

		// Add the "tab-like" box around the time
		g2d.drawRoundRect(0, 0, 32, height, 15, 15);

		// Add the "tab-like" box around the days
		for (int i = 0; i < 18; i++) {
			g2d.drawRoundRect(32 + i * x, 0, x, height, 15, 15);
		}

		/*
		 * //Vertical lines for (int i = 0; i < 7; i++) { g2d.drawLine(32 + i *
		 * x, 0, 32 + i * x, height); }
		 */
		// Horisontal lines
		for (int i = 1; i < 18; i++) {
			g2d.drawLine(0, i * y, width, i * y);
		}

	}

	private void drawText() {
		g2d.setColor(Color.BLACK);

		x = (int) ((width - 32d) / 7d);
		for (int i = 0; i < 7; i++) {

			try {
				g2d.drawString(days.get(i), (int) (x / 1.8d) + x * i, 15);
			} catch (Exception E) {

			}
		}

		g2d.drawString("Tid", 2, 18);

		for (int i = 0; i < 17; i++) {
			if (i < 4) {
				g2d.drawString("0" + (i + 6) + ":" + "00", 1, (i + 1) * y + 12);
			} else {
				g2d.drawString(i + 6 + ":" + "00", 1, (i + 1) * y + 12);
			}
		}

	}

	private void drawAppointments() {
		// get all appointments.
		if (abs == null || true) {
			abs = getAppointmentBoxes();
		} else {
			// does not function propperly yet.
			abs = updateAppointmentBoxes();
		}

		// Tr�d tr�bbel. Vi burde ha locks
		ArrayList<AppointmentBox> tempABS = (ArrayList<AppointmentBox>) abs
				.clone();
		for (AppointmentBox ab : tempABS) {

			ab.draw(g2d, x, y, width / 7, height, calHelp);
		}

	}

	private ArrayList<AppointmentBox> updateAppointmentBoxes() {

		// System.out.println("First: "+firstVisibleDate.getHours()+" "+firstVisibleDate.getMinutes()+"Last: "+lastVisibleDate.toString());
		aps = Appointment.getAppointmentsBetween(Person.getCurrentUser(),
				firstVisibleDate, lastVisibleDate);

		return null;
	}

	private ArrayList<AppointmentBox> getAppointmentBoxes() {

		// List<Appointment> aps =
		// Appointment.getAppointmentsFor(Person.getCurrentUser());
		firstVisibleDate = calHelp.getFirstDayInCurrentWeek();
		lastVisibleDate = calHelp.getLastDayInCurrentWeek();
		// System.out.println("First: "+firstVisibleDate.toString()+". Last: "+lastVisibleDate.toString());

		// System.out.println("Apps"
		// + Appointment.getAppointmentsFor(Person.getCurrentUser())
		// .size());
		Person ourGuy;
		Person selectedValue = (Person) jList.getSelectedValue();
		if (selectedValue != null) {
			ourGuy = selectedValue;
		} else {
			ourGuy = Person.getCurrentUser();
		}
		
		if (false) {
			for (Appointment app : Appointment.getAppointmentsFor(ourGuy)) {
				if (app.getOwner() != null) {
					System.out.println("Owner: " + app.getOwner().id + ". "
							+ app.getStartDate().toString());
				}
			}
		}
		aps = Appointment.getAppointmentsBetween(ourGuy,
				firstVisibleDate, lastVisibleDate);

		abs = new ArrayList<AppointmentBox>();

		// System.out.println("First date:"+firstVisibleDate.getDate()+" "+firstVisibleDate.getYear()+". TIME:"+firstVisibleDate.getTime()+". Now:"+Calendar.getInstance().getTimeInMillis()+". DeltaFirst: "+(Calendar.getInstance().getTimeInMillis()-firstVisibleDate.getTime())+". DeltaLast: "+(Calendar.getInstance().getTimeInMillis()-lastVisibleDate.getTime()));
		for (Appointment ap : aps) {
			abs.add(new AppointmentBox(ap));
		}

		return abs;
	}

	@Override
	public void run() {

		while (getPeer() == null) {
			try {
				Thread.sleep(2);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		createBufferStrategy(2);
		_buffStrategy = this.getBufferStrategy();
		if (_buffStrategy != null) {
			g2d = (Graphics2D) _buffStrategy.getDrawGraphics();
		} else {

			System.err.println("why is this null?");
		}

		basicStroke = g2d.getStroke();

		while (alive) {
			lastTime = System.currentTimeMillis();

			draw();

			_now = System.currentTimeMillis();
			if (1000 - (_now - lastTime) > 0) {
				try {
					Thread.sleep(1000 - (_now - lastTime));
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}

		}
	}

	/**
	 * Finds the appropriate x position for the provided date.
	 * 
	 * @param theDate
	 * @return
	 */
	public int getXposFromDate(Date theDate) {

		return ((getDay(theDate) - getDay(calHelp.getFirstCalendarDayDate()) + 7) % 7)
				* x + 32;
	}

	/**
	 * 
	 * @param theDate
	 * @param start
	 * @return
	 */
	public int getYposFromDate(Time theDate) {
		if (theDate != null) {
			if (theDate.getMinutes() != 0) {
				return (int) ((theDate.getHours() - 5) * y)
						+ (int) ((y + 1) * ((double) (theDate.getMinutes()) / 60d));
				// System.out.println(min);
			}
			return (int) ((theDate.getHours() - 5) * y);

		}

		return -1;
	}

	/**
	 * Find day of the week
	 * 
	 * @param date
	 * @return Monday = 0... Sunday = 6.
	 */
	public static int getDay(Date date) {
		if (date != null) {
			return (date.getDay() + 6) % 7;
		}
		return -100000;
	}

	@Override
	public void mouseClicked(MouseEvent arg0) {

		boolean t = false;

		for (AppointmentBox ab : abs) {
			if (ab.isPointInside(arg0.getPoint())) {
				// this box was clicked
				t = true;
				pop = new Popupmenu(ab.getMyAppointment());
				pop.setUndecorated(true);
				pop.setLocation(arg0.getXOnScreen()
						- (int) (pop.getWidth() / 2d), arg0.getYOnScreen()
						- (int) (pop.getHeight() / 2d));
				pop.setVisible(true);
				pop.setAlwaysOnTop(true);
				pop.addWindowFocusListener(new WindowFocusListener() {

					@Override
					public void windowLostFocus(WindowEvent e) {
						// TODO Auto-generated method stub
						pop.setVisible(false);
					}

					@Override
					public void windowGainedFocus(WindowEvent e) {
					}
				});
				// ab.getMyAppointment();

			}
		}
		if (!t && pop != null) {
			dispatchEvent(new WindowEvent(pop, WindowEvent.WINDOW_CLOSING));
		}
	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
	}

	@Override
	public void mouseExited(MouseEvent arg0) {
	}

	@Override
	public void mousePressed(MouseEvent arg0) {
	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
	}

	@Override
	public void mouseMoved(MouseEvent arg0) {
	}

	@Override
	public void mouseDragged(MouseEvent e) {
	}

	public Appointment getAppointmentAt(Point point) {

		Appointment.getAppointmentsBetween(Person.getCurrentUser(),
				firstVisibleDate, lastVisibleDate);

		return null;
	}

}
